package com.vizhuo.base.controller;

import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.vizhuo.base.model.BaseModel;
import com.vizhuo.base.service.BaseServiceI;

import com.vizhuo.utils.Constants;
import com.vizhuo.utils.StorageIdsModel;

/**
 * <pre>
 * 控制层实现，提供基本的单对象CRUD操作方法
 * 各方法的@RequestMapping注解可以在子类中继承
 * 业务层方法命名需严格遵循以下规则：
 * 1、添加：add开头
 * 2、更新：modify开头
 * 3、删除：remove开头
 * 4、查询：find开头
 * </pre>
 * 
 * @author 刘大年
 * 
 * @param <T>
 */
public class BaseController<T, U, I> {

    private static Logger log = LoggerFactory.getLogger(BaseController.class);

    /**
     * 泛型实体的className，主要用于storageIdsInSession方法中 在子类中进行赋值
     */
    protected String modelName;

    /**
     * service实例，通过spring注解获得
     */
    protected BaseServiceI<T, U, I> baseService;

    /**
     * 模块jsp页面前缀，包含所在目录及文件名中所包含的实体名称，如"sys/user/jsp/User"->对应页面sys/user/jsp/
     * UserList.jsp(UserAdd.jsp UserEdit.jsp) 用于动态forward返回，redirect不可用，
     * 
     */
    protected String jspPrefix;

    /**
     * 添加、更新操作后跳转的成功页面，用于提示成功信息和刷新父窗口
     */
    protected static String SUCCESS_PATH = "/global/jsp/success.jsp";

    /**
     * 是否将对象列表页的id集合进行暂存，主要用于关键数据修改、删除前的判断 以保证只有查看过的数据才能进行修改和删除操作
     */
    protected boolean STORAGE_IDS = false;

    /**
     * id集合放在session中的key
     */
    protected final static String STORAGE_SESSION_KEY = "storageIdsModel";

    /**
     * json在model中的名字
     */
    protected final static String MODEL_JSON = "json";

    /**
     * 跳转至add页面
     * 
     * @param request
     * @param session
     * @return
     */
    @RequestMapping("/toAdd")
    public String toAdd(T entity, Model model, HttpServletRequest request, HttpSession session) {
        beforToAdd(entity, model, request, session);
        model.addAttribute("entity", entity);
        return getJspPrefix() + "Add";
    }

    /**
     * toAdd前置方法
     */
    public void beforToAdd(T entity, Model model, HttpServletRequest request, HttpSession session) {

    }

    /**
     * 添加对象方法
     * 
     * @return 默认redirect到操作成功页面SUCCESS_PATH
     */
    @RequestMapping("/add")
    public String addEntity(T entity, Model model, RedirectAttributes redirectAttributes, HttpServletRequest request,
            HttpSession session) {
        beforAddEntity(entity, model, redirectAttributes, request, session);
        int msg = baseService.addEntity(entity);
        redirectAttributes.addFlashAttribute("msg", msg + "条数据操作成功！");
        afterAddEntity(entity, model, redirectAttributes, request, session);
        return "redirect:" + SUCCESS_PATH;
    }

    /**
     * addEntity前置方法，父类中进行初始化操作，子类在继承是应该先调用super.beforAddEntity()
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void beforAddEntity(T entity, Model model, RedirectAttributes redirectAttributes,
            HttpServletRequest request, HttpSession session) {
        entity = initAddEntity(entity, session);
    }

    /**
     * 初始化要添加的对象
     * 
     * @param session
     */
    @SuppressWarnings("rawtypes")
    public T initAddEntity(T entity, HttpSession session) {
        // 获取当前登录用户
        //User sessionUser = (User) session.getAttribute(Constants.SESSION_USER);
//        BaseModel bm = (BaseModel) entity;
//        bm.setCreateDatetime(new Date());
//        bm.setLastModifyDatetime(new Date());
//        bm.setCreateUserId(sessionUser.getId());
//        bm.setLastModifyUserId(sessionUser.getId());
        return entity;
    }

    /**
     * addEntity后置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void afterAddEntity(T entity, Model model, RedirectAttributes redirectAttributes,
            HttpServletRequest request, HttpSession session) {

    }

    /**
     * 获得所有用户，无分页
     * 
     * @param entity
     * @param request
     * @param session
     * @return
     */
    @RequestMapping("/findAll")
    public String findAllEntity(Model model, HttpServletRequest request, HttpSession session) {
        beforFindAllEntity(model, request, session);
        List<T> entityList = baseService.findAllEntity();
        model.addAttribute("entityList", entityList);
        if (STORAGE_IDS) {
            // 如果需要验证查看权限，在此时将结果集id放入session
            storageIdsInSession(entityList, session);
        }
        afterFindAllEntity(model, request, session);
        return getJspPrefix() + "List";
    }

    /**
     * findAllEntity前置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void beforFindAllEntity(Model model, HttpServletRequest request, HttpSession session) {

    }

    /**
     * findAllEntity后置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void afterFindAllEntity(Model model, HttpServletRequest request, HttpSession session) {

    }

 

    /**
     * 根据ID删除用户
     * 
     * @return 默认redirect到分页查询方法findEntityByPager.do
     */
    @RequestMapping("/removeByID")
    public String removeEntityByID(@RequestParam("id")
    I id, T entity, Model model, RedirectAttributes redirectAttributes, HttpServletRequest request, HttpSession session) {
        beforRemoveEntityByID(id, entity, model, redirectAttributes, request, session);
        // 如果需要验证查看权限，且id不存在session中，则报错返回
        if (STORAGE_IDS && !isIDINSession(id, session)) {
            redirectAttributes.addFlashAttribute("errorMsg", "您没有修改此数据的权限！");
            return "redirect:toError.do";
        }

        baseService.removeEntityByID(id);
        redirectAttributes.addFlashAttribute("msg", "操作成功！");
        afterRemoveEntityByID(id, entity, model, redirectAttributes, request, session);
        return "redirect:findByPager.do";
    }

    /**
     * removeEntityByID前置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void beforRemoveEntityByID(I id, T entity, Model model, RedirectAttributes redirectAttributes,
            HttpServletRequest request, HttpSession session) {
        entity = initModifyEntity(entity, session);
    }

    /**
     * 初始化要修改的对象
     * 
     * @param session
     */
    @SuppressWarnings("rawtypes")
    public T initModifyEntity(T entity, HttpSession session) {
        // 获取当前登录用户
//        User sessionUser = (User) session.getAttribute(Constants.SESSION_USER);
//        BaseModel bm = (BaseModel) entity;
//        bm.setLastModifyDatetime(new Date());
//        bm.setLastModifyUserId(sessionUser.getId());
        return entity;
    }

    /**
     * removeEntityByID后置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void afterRemoveEntityByID(I id, T entity, Model model, RedirectAttributes redirectAttributes,
            HttpServletRequest request, HttpSession session) {

    }

    /**
     * 根据id获得实体信息，此方法为findEntityInfo和findOneEntity共同部分，所以单独提出
     * 
     * @param id
     * @param redirectAttributes
     * @param model
     * @param request
     * @param session
     * @return
     */
    public boolean findEntityByID(I id, RedirectAttributes redirectAttributes, Model model, HttpServletRequest request,
            HttpSession session) {
        // 如果需要验证查看权限，且id不存在session中，则报错返回
        if (STORAGE_IDS && !isIDINSession(id, session)) {
            redirectAttributes.addFlashAttribute("errorMsg", "您没有修改此数据的权限！");
            // return "redirect:toError.do";
            return false;
        }

        T entity = baseService.findOneEntity(id);
        model.addAttribute("entity", entity);
        return true;
    }

    /**
     * 查询用户详细信息并显示
     * 
     * @param id
     * @param redirectAttributes
     * @param model
     * @param request
     * @param session
     * @return
     */
    @RequestMapping("/findInfo")
    public String findEntityInfo(I id, RedirectAttributes redirectAttributes, Model model, HttpServletRequest request,
            HttpSession session) {
        beforFindEntityInfo(id, redirectAttributes, model, request, session);
        if (findEntityByID(id, redirectAttributes, model, request, session)) {
            afterFindEntityInfo(id, redirectAttributes, model, request, session);
            return getJspPrefix() + "Info";
        } else {
            return "redirect:toError.do";
        }

    }

    /**
     * findEntityInfo前置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void beforFindEntityInfo(I id, RedirectAttributes redirectAttributes, Model model,
            HttpServletRequest request, HttpSession session) {

    }

    /**
     * findEntityInfo后置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void afterFindEntityInfo(I id, RedirectAttributes redirectAttributes, Model model,
            HttpServletRequest request, HttpSession session) {

    }

    /**
     * 进入编辑页面前根据id获取用户信息
     * 
     * @return 默认跳转编辑页面edit
     * @throws Exception
     */
    @RequestMapping("/findOne")
    public String findOneEntity(I id, RedirectAttributes redirectAttributes, Model model, HttpServletRequest request,
            HttpSession session) {
        beforFindOneEntity(id, redirectAttributes, model, request, session);
        if (findEntityByID(id, redirectAttributes, model, request, session)) {
            // 成功才执行after方法
            afterFindOneEntity(id, redirectAttributes, model, request, session);
            return getJspPrefix() + "Edit";
        } else {
            return "redirect:toError.do";
        }
    }

    /**
     * findOneEntity前置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void beforFindOneEntity(I id, RedirectAttributes redirectAttributes, Model model,
            HttpServletRequest request, HttpSession session) {

    }

    /**
     * findOneEntity后置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void afterFindOneEntity(I id, RedirectAttributes redirectAttributes, Model model,
            HttpServletRequest request, HttpSession session) {

    }

    /**
     * 更新一个用户的信息
     * 
     * @return 默认返回
     */
    @RequestMapping("/modify")
    public String modifyEntity(I id, T entity, Model model, RedirectAttributes redirectAttributes,
            HttpServletRequest request, HttpSession session) {
        beforModifyEntity(id, entity, model, redirectAttributes, request, session);
        // 如果需要验证查看权限，且id不存在session中，则报错返回
        if (STORAGE_IDS && !isIDINSession(id, session)) {
            redirectAttributes.addFlashAttribute("errorMsg", "您没有修改此数据的权限！");
            return "redirect:toError.do";
        }

        int msg = 0;
        try {
            msg = baseService.modifyEntity(entity);
            redirectAttributes.addFlashAttribute("msg", msg + "条数据操作成功！");
        } catch (Exception e) {
            // 如果发生异常，事务回滚
            redirectAttributes.addFlashAttribute("errorMsg", "事务异常据，操作失败！");
            log.error(e.getMessage());
            return "redirect:toError.do";
        }

        afterModifyEntity(id, entity, model, redirectAttributes, request, session);
        return "redirect:" + SUCCESS_PATH;
    }

    /**
     * modifyEntity前置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void beforModifyEntity(I id, T entity, Model model, RedirectAttributes redirectAttributes,
            HttpServletRequest request, HttpSession session) {
        entity = initModifyEntity(entity, session);
    }

    /**
     * modifyEntity后置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void afterModifyEntity(I id, T entity, Model model, RedirectAttributes redirectAttributes,
            HttpServletRequest request, HttpSession session) {

    }

    /**
     * 通过id批量删除用户
     * 
     * @param ids
     * @param model
     * @return 返回页面/success.jsp
     */
    @RequestMapping("/batchRemove")
    public String batchRemoveEntities(@RequestParam("ids")
    I[] ids, Model model, RedirectAttributes redirectAttributes, HttpServletRequest request, HttpSession session) {
        beforBatchRemoveEntities(ids, model, redirectAttributes, request, session);
        boolean idsIsNotEmpty = (ids != null && ids.length > 0);

        if (idsIsNotEmpty) {
            // ids集合不为空
            if (STORAGE_IDS && !isIDINSession(ids, session)) {
                // 如果需要验证查看权限，且ids不存在session中，则报错返回
                redirectAttributes.addFlashAttribute("errorMsg", "您没有修改此数据的权限！");
                return "redirect:toError.do";
            }
            // I[] idsInt = ArrayUtils.toPrimitive(ids);
            int msg = baseService.removeEntities(ids);
            redirectAttributes.addFlashAttribute("msg", msg + "条数据操作成功！");
            // 只在成功后调用afterRemoveEntities，其他结果不与考虑
            afterBatchRemoveEntities(ids, model, redirectAttributes, request, session);
            return "redirect:findByPager.do";
        } else {
            // ids集合为空
            redirectAttributes.addFlashAttribute("errorMsg", "请选择要删除的数据并重新进行操作！");
            return "redirect:toError.do";
        }
    }

    /**
     * batchRemoveEntities前置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void beforBatchRemoveEntities(I[] ids, Model model, RedirectAttributes redirectAttributes,
            HttpServletRequest request, HttpSession session) {

    }

    /**
     * batchRemoveEntities后置方法
     * 
     * @param entity
     * @param redirectAttributes
     * @param request
     * @param session
     */
    public void afterBatchRemoveEntities(I[] ids, Model model, RedirectAttributes redirectAttributes,
            HttpServletRequest request, HttpSession session) {

    }

    /**
     * 将列表中的对象名称和id集合放入session中，session的key为"storageIdsModel"
     * 
     * @param entityList
     */
    @SuppressWarnings("rawtypes")
    public void storageIdsInSession(List<T> entityList, HttpSession session) {
        // 实例化一个对象
        StorageIdsModel sim = new StorageIdsModel();
        // 获取实体类名
        sim.setEntityName(modelName);

        if (entityList != null) {
            // 由于id类型各不相同，所以采用Object数组存放
            Object[] objArray = new Object[entityList.size()];
            // 循环放入数组中
            for (int i = 0; i < entityList.size(); i++) {
                BaseModel entity = (BaseModel) entityList.get(i);
                objArray[i] = entity.getId();
            }

            sim.setIdArray(objArray);
        }
        session.setAttribute(STORAGE_SESSION_KEY, sim);
    }

    /**
     * 判断对象的id是否在session中存在
     * 
     * @param entity
     * @return
     */
    public boolean isIDINSession(I id, HttpSession session) {
        StorageIdsModel sim = (StorageIdsModel) session.getAttribute(STORAGE_SESSION_KEY);
        if (sim == null) {
            return false;
        }

        // 先验证类名，再验证id
        String entityName = sim.getEntityName();
        if (!entityName.equals(modelName)) {
            return false;
        }

        // 获得id
        Object[] objArray = sim.getIdArray();
        if (ArrayUtils.isEmpty(objArray)) {
            return false;
        }
        // 验证id
        for (int i = 0; i < objArray.length; i++) {
            Object o = objArray[i];
            if (id.equals(o)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断对象的id集合是否在session中存在
     * 
     * @param ids
     * @return
     */
    public boolean isIDINSession(I[] ids, HttpSession session) {
        if (!ArrayUtils.isEmpty(ids)) {
            for (int i = 0; i < ids.length; i++) {
                if (!isIDINSession(ids[i], session)) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * 初始化
     * 
     * @param request
     * @param response
     */
    public void init(HttpServletRequest request, HttpServletResponse response) {
        setResponseCoding(request, response);
    }

    /**
     * 设置printWrite
     * 
     * @param response
     */
    public void setResponseCoding(HttpServletRequest request, HttpServletResponse response) {
        String encoding = request.getParameter("encoding");
        if (StringUtils.isBlank(encoding)) {
            response.setCharacterEncoding("UTF-8");
        } else {
            response.setCharacterEncoding(encoding);
        }
    }

    /**
     * 跳转至错误页面，通过此方法跳转可以显示redirectAttributes.addFlashAttribute()中的信息
     * 
     * @return
     */
    @RequestMapping("toError")
    public String toError() {
        return "global/jsp/error";
    }

    @RequestMapping("json")
    public String json() {
        return "global/jsp/json";
    }

    public BaseServiceI<T, U, I> getBaseService() {
        return baseService;
    }

    public void setBaseService(BaseServiceI<T, U, I> baseService) {
        this.baseService = baseService;
    }

    public String getJspPrefix() {
        return jspPrefix;
    }

    public void setJspPrefix(String jspPrefix) {
        this.jspPrefix = jspPrefix;
    }

}
